package
{
	import flash.events.Event;
	
	import org.flixel.*; 

	public class LoadPuzzlesState extends FlxState
	{
		// positioning constants
		private const TAB_HEIGHT:int = 50;
		private const CONTAINER_WIDTH:int = FlxG.width - 100;
		private const CONTAINER_HEIGHT:int = FlxG.height - TAB_HEIGHT - 100;
		private const CONTAINER_START_X:int = (FlxG.width - CONTAINER_WIDTH) / 2;
		private const CONTAINER_START_Y:int = ((FlxG.height - CONTAINER_HEIGHT - TAB_HEIGHT)/2) + TAB_HEIGHT;
		
		private const EASY:int = 0;
		private const MEDIUM:int = 1;
		private const HARD:int = 2;
		
		// listings vectors
		private var easyListings:Array;
		private var mediumListings:Array;
		private var hardListings:Array;
		
		// are we displaying easy, medium or hard?
		private var currentType:int; 
		private var currentPage:int;
		
		private var container:FlxSprite;
		private var body:FlxSprite;
		private var listings:FlxGroup;
		
		//tabs
		private var easyTab:FlxSprite;
		private var easyLabel:FlxText;
		private var mediumTab:FlxSprite;
		private var mediumLabel:FlxText;
		private var hardTab:FlxSprite;
		private var hardLabel:FlxText;
		
		// footer
		private var pageNum:FlxText;
		private var prevPage:FlxText;
		private var nextPage:FlxText;
		
		// other stuffs
		private var loadingText:FlxText;
		private var loadingSprite:LoadingIndicator;
		private var emptySign:FlxText;
		private var exitButton:FlxSprite;
		
		private var loading:Boolean;

		public function LoadPuzzlesState()
		{
			super();
			
			// Log that the user has entered the puzzle loader!
			Elemental.Log.startDquest(Logging.PUZZLE_LOADER);
			
			initLayout();
			
			currentType = -1;
			currentPage = 1;
			loading = false;
			
			requestData(EASY);
		}
		
		/**
		 * Draw the container, tabs, exit button, etc.
		 */
		public function initLayout():void {
			add(new FlxSprite(0,0, Res.bg));

			container = new FlxSprite();
			container.makeGraphic(CONTAINER_WIDTH, CONTAINER_HEIGHT);
			container.drawRect(0, 0, CONTAINER_WIDTH, CONTAINER_HEIGHT, 0x091340);
			container.x = CONTAINER_START_X;
			container.y = CONTAINER_START_Y;
			add(container);
			
			easyTab = createTab(true, container.x, container.y - 50);
			add(easyTab);
			
			easyLabel = new FlxText(easyTab.x, easyTab.y, easyTab.width, "Easy", false);
			easyLabel.setFormat("Courier New", 36, 0xffffff, "center", 1, true);
			add(easyLabel);
			
			mediumTab = createTab(false, easyTab.x + easyTab.width + 10, easyTab.y);
			add(mediumTab);
			
			mediumLabel = new FlxText(mediumTab.x, mediumTab.y, mediumTab.width, "Medium", false);
			mediumLabel.setFormat("Courier New", 36, 0xffffff, "center", 1, true);
			add(mediumLabel);
			
			hardTab = createTab(false, mediumTab.x + mediumTab.width + 10, mediumTab.y);
			add(hardTab);
			
			hardLabel = new FlxText(hardTab.x, hardTab.y, hardTab.width, "Hard", false);
			hardLabel.setFormat("Courier New", 36, 0xffffff, "center", 1, true);
			add(hardLabel);
			
			body = new FlxSprite();
			body.makeGraphic(CONTAINER_WIDTH - 50, CONTAINER_HEIGHT-50, 0x000000, true);
			body.drawRect(0, 0, CONTAINER_WIDTH - 50, CONTAINER_HEIGHT-50, 0x444444);
			body.x = container.x + 25;
			body.y = container.y + 25;
			add(body);
			
			exitButton = new FlxSprite(0, 0, Res.ExitButton);
			exitButton.x = FlxG.width - exitButton.width - 5;
			exitButton.y = 5;
			add(exitButton);
			
			createPageFooter();
			
			listings = new FlxGroup();
			add(listings);
			
			loadingText = new FlxText(0, 0, body.width, "Loading puzzles ...", false);
			loadingText.setFormat("Courier New", 24, 0xFFFFFF, "center", 1, true);
			loadingText.x = body.x + (body.width - loadingText.width)/2;
			loadingText.y = body.y + (body.height - loadingText.height)/2 - 20;
			
			loadingSprite = new LoadingIndicator(0, 0);
			loadingSprite.x = body.x + (body.width - loadingSprite.width)/2;
			loadingSprite.y = loadingText.y + loadingText.height + 10;
			
			emptySign = new FlxText(0, 0, body.width, "No puzzles available", false);
			emptySign.setFormat("Courier New", 24, 0xFFFFFF, "center", 1, true);
			emptySign.x = body.x + (body.width - emptySign.width)/2;
			emptySign.y = body.y + (body.height - emptySign.height)/2;
		}
		
		/**
		 * If a tab is clicked, make it focused, and do another request if necessary.
		 */
		public override function update():void {
			super.update();
			
			if (FlxG.mouse.justPressed()) {
				
				if (easyTab.overlapsPoint(FlxG.mouse.screenX, FlxG.mouse.screenY) && !loading) {
					easyTab.loadGraphic(Res.tabEnabled);
					mediumTab.loadGraphic(Res.tabDisabled);
					hardTab.loadGraphic(Res.tabDisabled);
					requestData(EASY);
				} 

				if (mediumTab.overlapsPoint(FlxG.mouse.screenX, FlxG.mouse.screenY) && !loading) {
					mediumTab.loadGraphic(Res.tabEnabled);
					easyTab.loadGraphic(Res.tabDisabled);
					hardTab.loadGraphic(Res.tabDisabled);
					requestData(MEDIUM);
				} 

				if (hardTab.overlapsPoint(FlxG.mouse.screenX, FlxG.mouse.screenY) && !loading) {
					hardTab.loadGraphic(Res.tabEnabled);
					mediumTab.loadGraphic(Res.tabDisabled);
					easyTab.loadGraphic(Res.tabDisabled);
					requestData(HARD);
				}
				
				if (exitButton.overlapsPoint(FlxG.mouse.screenX, FlxG.mouse.screenY) && !loading) {
					if (Elemental.MODE == Elemental.FACEBOOK_MODE) {
						FlxG.switchState(new PlayerRoomState());
					} else {
						FlxG.switchState(new MenuState());
					}
				}
				
				if (prevPage.overlapsPoint(FlxG.mouse.screenX, FlxG.mouse.screenY)) {
					requestNewPage(currentPage - 1);
				}
				
				if (nextPage.overlapsPoint(FlxG.mouse.screenX, FlxG.mouse.screenY)) {
					requestNewPage(currentPage + 1);
				}
			}
		}
		
		/**
		 * Returns a tab flxsprite with appropriate focused/unfocused background
		 */
		private function createTab(enabled:Boolean, x:int, y:int):FlxSprite {
			var bg:Class = enabled ? Res.tabEnabled : Res.tabDisabled;
			var tab:FlxSprite = new FlxSprite(x, y, bg);
			return tab;
		}
		
		/**
		 * Clears all items in the container and makes a request to server.
		 * Called when a tab is clicked or when this class is initialized.
		 * Adds loading graphic, resets current page num to 1.
		 */
		private function requestData(type:int):void {
			// Do not redraw listings if we're already on that tab.
			if (type == currentType) {
				return;
			} else {
				currentType = type;
				currentPage = 1;
				
				// clear the page
				listings.clear();
				remove(pageNum)
				remove(prevPage);
				remove(nextPage);
				remove(emptySign);
				
				// Check if we haven't got the data yet.
				if ((currentType == EASY && easyListings == null)
					|| (currentType == MEDIUM && mediumListings ==null)
					|| (currentType == HARD && hardListings == null)) {
					add(loadingText);
					add(loadingSprite);
					loading = true;
					
					if (Elemental.MODE == Elemental.NORMAL_MODE) {
						trace("in normal mode");
						Client.loadAllPuzzlesByDifficulty(currentType, loadData);
					} else if (Elemental.MODE == Elemental.FACEBOOK_MODE) {
						trace("in facebook mode");
						Client.loadAllPuzzlesByDifficultyForFB(currentType, loadData);
					}
				} else {
					if (getListingsByDifficulty(currentType).length == 0) {
						add(emptySign);
					} else {
						updateListings(currentPage);
					}
				}
			}
		}
		
		/**
		 * Called when the page arrows are clicked.
		 * Precondition: we already have data for this difficulty type.
		 * Does nothing if the requested page is invalid.
		 */
		private function requestNewPage(requestedPage:int):void {
			var totalPages:int = Math.ceil(getListingsByDifficulty(currentType).length / 5);
			if (requestedPage < 1 || requestedPage > totalPages) {
				return;
			}
			
			currentPage = requestedPage;
			listings.clear();
			remove(pageNum);
			remove(prevPage);
			remove(nextPage);
			
			updateListings(requestedPage);
		}
		
		/**
		 * Called when our client has received data from the server.
		 * Removes loading graphic, creates a listing for five puzzles.
		 */
		private function loadData(e:Event):void {
			var maps:String = e.target.data;
			trace("returned " + e.target.data);
			
			if (maps == "no maps") {
				remove(loadingText);
				remove(loadingSprite);
				loading = false;
				add(emptySign);
				
				if (currentType == EASY) {
					easyListings = new Array();
				} else if (currentType == MEDIUM) {
					mediumListings = new Array();
				} else {
					hardListings = new Array();
				}
				
			} else {
				var mapArray:Array = maps.split("/");
				
				if (currentType == EASY) {
					easyListings = mapArray;
				} else if (currentType == MEDIUM) {
					mediumListings = mapArray;
				} else {
					hardListings = mapArray;
				}
				
				loading = false;
				remove(loadingText);
				remove(loadingSprite);
				updateListings(currentPage);
			}
		}
		
		/**
		 * Grabs the listings for the requested batch, and updates the footer.
		 * Precondition: assumes data exists.
		 */
		private function updateListings(pageNum:int):void {
			var startIndex:int = (pageNum-1)*5;
			for (var i:int = 0; i < 5; i++) {
				var xPos:int = body.x + 15;
				var yPos:int = body.y + (PuzzleListing.LISTING_HEIGHT * i) + ((i+1) * 15);
				
				if (startIndex + i >= getListingsByDifficulty(currentType).length) {
					break;
				}
				
				var spec:String = getListingsByDifficulty(currentType)[startIndex + i];
				var specArray:Array = spec.split(":");
				
				var listing:PuzzleListing = new PuzzleListing(specArray[2], specArray[1], specArray[8], spec, xPos, yPos);
				listings.add(listing);
			}
			
			var totalPages:int = Math.ceil(getListingsByDifficulty(currentType).length / 5);
			updateFooter(pageNum, totalPages);
		}
		
		/**
		 * Initializes footer text (but not added to stage)
		 */
		private function createPageFooter():void {
			pageNum = new FlxText(0, 0, body.width, "Page 1 of 15", false);
			pageNum.setFormat("Courier New", 26, 0xFFFFFF, "center", 1, true);
			pageNum.x = body.x + (body.width - pageNum.width)/2;
			pageNum.y = body.y + body.height - 10 - pageNum.height;
			
			prevPage = new FlxText(0, 0, 100, "<<", false);
			prevPage.setFormat("Courier New", 26, 0xFFFFFF, "right", 1, true);
			prevPage.x = body.x + 10;
			prevPage.y = pageNum.y;
			
			nextPage = new FlxText(0, 0, 100, ">>", false);
			nextPage.setFormat("Courier New", 26, 0xFFFFFF, "left", 1, true);
			nextPage.x = body.x + body.width - 10 - nextPage.width;
			nextPage.y = pageNum.y;
		}
		
		/**
		 * Updates footer text depending on current page.
		 */
		private function updateFooter(currPage:int, totalPages:int):void {
			pageNum.text = "Page " + currPage + " of " + totalPages;
			add(pageNum);
			
			if (currPage > 1) add(prevPage);
			if (currPage < totalPages) add(nextPage);
		}
		
		/**
		 * Returns the correct vector by difficulty.
		 */
		private function getListingsByDifficulty(difficulty:int):Array {
			if (currentType == EASY) {
				return easyListings;
			} else if (currentType == MEDIUM) {
				return mediumListings;
			} else {
				return hardListings;
			}
		}
	}
}